<?php

#<editor-fold defaultstate="collapsed" desc="CCore::Using">
CCore::Using('base.utils');
CCore::Using('base.log');
CCore::Using('socket.inc.constants');
CCore::Using('socket.inc.abstract');
CCore::Using('socket.smtp.config');
CCore::Using('socket.smtp.message');
#</editor-fold>

class CCoreSocketSmtp extends ACoreSocket
{
	/**
	 * @param	CCoreSocketSmtpConfig	$oImapConfig
	 * @param	array					$aFollowers = array()
	 * @return	CCoreSocketSmtp
	 */
	public function __construct(CCoreSocketSmtpConfig $oSmtpConfig, $aFollowers = array())
	{
		CCore::CheckTypes(array('$oSmtpConfig', '$aFollowers'));

		$oDevelopments = new CCoreBaseDevelopments('SMTP', 'SMTP[Error]', 'SMTP[Warning]', 'SMTP[Notice]');
		$oDevelopments->AddArray($aFollowers);

		parent::__construct($oSmtpConfig, $oDevelopments);
	}

	/**
	 * @return	void
	 */
	public function __destruct()
	{
		$this->LogoutAndDisconnect();
	}

	/**
	 * @return	bool
	 */
	public function Connect()
	{
		$iPort = $this->oConfig->GetValue('Port', 'int');
		
		return parent::Connect(465 === $iPort) && $this->_isSuccess();
	}

	/**
	 * @return	bool
	 */
	public function Login()
	{
		$sEhloMessage = $this->oConfig->GetValue('EhloMessage', 'string');
		if (!$this->_executeCommand('EHLO '.$sEhloMessage))
		{
			if (!$this->_executeCommand('HELO '.$sEhloMessage))
			{
				return false;
			}
		}

		$bIsAuth = $this->oConfig->GetValue('IsAuth', 'boolean');
		if ($bIsAuth)
		{
			$sLogin = $this->oConfig->GetValue('Login', 'string');
			$sPassword = $this->oConfig->GetValue('Password', 'string');

			if (!$this->_executeCommand('AUTH LOGIN') ||
				!$this->_executeCommand(base64_encode($sLogin)) ||
				!$this->_executeCommand(base64_encode($sPassword)))
			{
				return false;
			}
		}
		
		return true;
	}

	/**
	 * @return	bool
	 */
	public function ConnectAndLogin()
	{
		return $this->Connect() && $this->Login();
	}

	/**
	 * @return	bool
	 */
	public function Logout()
	{
		return $this->_executeCommand('QUIT');
	}

	/**
	 * @return	bool
	 */
	public function LogoutAndDisconnect()
	{
		return $this->Logout() && $this->Disconnect();
	}

	/**
	 * @param	CCoreSocketSmtpMessage	$oSmtpMessage
	 * @return	bool
	 */
	public function SendMessage(CCoreSocketSmtpMessage $oSmtpMessage)
	{
		CCore::CheckTypes(array('$oSmtpMessage'));

		$aTo = $oSmtpMessage->ToAsArray();
		$aTo = array_unique($aTo);

		if (count($aTo) > 0)
		{
			if (!$this->_executeCommand('MAIL FROM:<'.$oSmtpMessage->FromAsString().'>'))
			{
				return false;
			}
		}
		else
		{
			$this->oDevelopments->Write('recipients not founds.', CCoreBaseDevelopments::WARNING);
			return false;
		}

		foreach ($aTo as $sRecipient)
		{
			if (!$this->_executeCommand('RCPT TO:<'.$sRecipient.'>'))
			{
				return false;
			}
		}

		if ($this->_executeCommand('DATA') &&
			$this->_executeCommand($this->_prepareDataForSend($oSmtpMessage->BodyAsString())))
		{
			return true;
		}

		return false;
	}
		
	/**
	 * @param	string	$sRawBody
	 * @return	string
	 */
	private function _prepareDataForSend($sRawBody)
	{
		CCore::CheckTypes(array('$sRawBody'));

		return str_replace(C_SOCKET_CRLF.'.', C_SOCKET_CRLF.'..', $sRawBody).C_SOCKET_CRLF.'.';
	}

	/**
	 * @param	string	$sCommand
	 * @return	bool
	 */
	private function _executeCommand($sCommand)
	{
		CCore::CheckTypes(array('$sCommand'));

		return $this->putLine($sCommand) && $this->_isSuccess();
	}
	/**
	 * @return	bool
	 */
	private function _isSuccess()
	{
		$sLine = '';
		$bResult = true;
		do
		{
			$sLine = $this->getLine();
			if (false === $sLine)
			{
				$bResult = false;
				break;
			}
			else
			{
				$sLine = str_replace(array("\r", "\n"), '', $sLine);
				$sFirstChar = substr($sLine, 0, 1);
				if ($sFirstChar !== '2' && $sFirstChar !== '3')
				{
					$bResult = false;
					$this->oDevelopments->Write('response not success ('.
						CCoreBaseUtils::ShowCRLF($sLine).').', CCoreBaseDevelopments::WARNING);
					break;
				}
			}

		} while (substr($sLine, 3, 1) === '-');

		return $bResult;
	}
}